home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / dosfile.c < prev    next >
C/C++ Source or Header  |  1994-02-11  |  25KB  |  1,147 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* DOS file handling routines */
  8.  
  9. #include "mint.h"
  10.  
  11. static long do_dup P_((int,int));
  12. static void unselectme P_((PROC *));
  13.  
  14. /*
  15.  * first, some utility routines
  16.  */
  17.  
  18. FILEPTR *
  19. do_open(name, rwmode, attr, x)
  20.     const char *name;    /* file name */
  21.     int rwmode;    /* file access mode */
  22.     int attr;    /* TOS attributes for created files (if applicable) */
  23.     XATTR *x;    /* filled in with attributes of opened file */
  24. {
  25.     struct tty *tty;
  26.     fcookie dir, fc;
  27.     long devsp;
  28.     FILEPTR *f;
  29.     DEVDRV *dev;
  30.     long r;
  31.     XATTR xattr;
  32.     unsigned perm;
  33.     int creating;
  34.     char temp1[PATH_MAX];
  35.     extern FILESYS proc_filesys;
  36.  
  37. /* for special BIOS "fake" devices */
  38.     extern DEVDRV fakedev;
  39.  
  40.     TRACE(("do_open(%s)", name));
  41.  
  42. /*
  43.  * first step: get a cookie for the directory
  44.  */
  45.  
  46.     r = path2cookie(name, temp1, &dir);
  47.     if (r) {
  48.         mint_errno = (int)r;
  49.         DEBUG(("do_open(%s): error %ld", name, r));
  50.         return NULL;
  51.     }
  52.  
  53. /*
  54.  * second step: try to locate the file itself
  55.  */
  56.     r = relpath2cookie(&dir, temp1, follow_links, &fc, 0);
  57.  
  58. /*
  59.  * file found: this is an error if (O_CREAT|O_EXCL) are set
  60.  */
  61.  
  62.     if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) ) {
  63.         DEBUG(("do_open(%s): file already exists",name));
  64.         mint_errno = EACCDN;
  65.         release_cookie(&fc);
  66.         release_cookie(&dir);
  67.         return NULL;
  68.     }
  69. /*
  70.  * file not found: maybe we should create it
  71.  * note that if r != 0, the fc cookie is invalid (so we don't need to
  72.  * release it)
  73.  */
  74.     if (r == EFILNF && (rwmode & O_CREAT)) {
  75.     /* check first for write permission in the directory */
  76.         r = (*dir.fs->getxattr)(&dir, &xattr);
  77.         if (r == 0) {
  78.             if (denyaccess(&xattr, S_IWOTH))
  79.                 r = EACCDN;
  80.         }
  81.         if (r) {
  82.             DEBUG(("do_open(%s): couldn't get "
  83.                   "write permission on directory",name));
  84.             mint_errno = (int)r;
  85.             release_cookie(&dir);
  86.             return NULL;
  87.         }
  88.         r = (*dir.fs->creat)(&dir, temp1,
  89.             (S_IFREG|DEFAULT_MODE) & (~curproc->umask), attr, &fc);
  90.         if (r) {
  91.             DEBUG(("do_open(%s): error %ld while creating file",
  92.                 name, r));
  93.             mint_errno = (int)r;
  94.             release_cookie(&dir);
  95.             return NULL;
  96.         }
  97.         creating = 1;
  98.     } else if (r) {
  99.         DEBUG(("do_open(%s): error %ld while searching for file",
  100.             name, r));
  101.         mint_errno = (int)r;
  102.         release_cookie(&dir);
  103.         return NULL;
  104.     } else {
  105.         creating = 0;
  106.     }
  107.  
  108. /*
  109.  * check now for permission to actually access the file
  110.  */
  111.     r = (*fc.fs->getxattr)(&fc, &xattr);
  112.     if (r) {
  113.         DEBUG(("do_open(%s): couldn't get file attributes",name));
  114.         mint_errno = (int)r;
  115.         release_cookie(&dir);
  116.         release_cookie(&fc);
  117.         return NULL;
  118.     }
  119. /*
  120.  * we don't do directories
  121.  */
  122.     if ( (xattr.mode & S_IFMT) == S_IFDIR ) {
  123.         DEBUG(("do_open(%s): file is a directory",name));
  124.         release_cookie(&dir);
  125.         release_cookie(&fc);
  126.         mint_errno = EFILNF;
  127.         return NULL;
  128.     }
  129.  
  130.     switch (rwmode & O_RWMODE) {
  131.     case O_WRONLY:
  132.         perm = S_IWOTH;
  133.         break;
  134.     case O_RDWR:
  135.         perm = S_IROTH|S_IWOTH;
  136.         break;
  137.     case O_EXEC:
  138.         perm = (fc.fs->fsflags & FS_NOXBIT) ? S_IROTH : S_IXOTH;
  139.         break;
  140.     case O_RDONLY:
  141.         perm = S_IROTH;
  142.         break;
  143.     default:
  144.         perm = 0;
  145.         ALERT("do_open: bad file access mode: %x", rwmode);
  146.     }
  147.     if (!creating && denyaccess(&xattr, perm)) {
  148.         DEBUG(("do_open(%s): access to file denied",name));
  149.         release_cookie(&dir);
  150.         release_cookie(&fc);
  151.         mint_errno = EACCDN;
  152.         return NULL;
  153.     }
  154.  
  155. /*
  156.  * an extra check for write access -- even the superuser shouldn't
  157.  * write to files with the FA_RDONLY attribute bit set (unless,
  158.  * we just created the file, or unless the file is on the proc
  159.  * file system and hence FA_RDONLY has a different meaning)
  160.  */
  161.     if ( !creating && (xattr.attr & FA_RDONLY) && fc.fs != &proc_filesys) {
  162.         if ( (rwmode & O_RWMODE) == O_RDWR ||
  163.              (rwmode & O_RWMODE) == O_WRONLY ) {
  164.             DEBUG(("do_open(%s): can't write a read-only file",
  165.                 name));
  166.             release_cookie(&dir);
  167.             release_cookie(&fc);
  168.             mint_errno = EACCDN;
  169.             return NULL;
  170.         }
  171.     }
  172.  
  173. /*
  174.  * if writing to a setuid or setgid file, clear those bits
  175.  */
  176.     if ( (perm & S_IWOTH) && (xattr.mode & (S_ISUID|S_ISGID)) ) {
  177.         xattr.mode &= ~(S_ISUID|S_ISGID);
  178.         (*fc.fs->chmode)(&fc, (xattr.mode & ~S_IFMT));
  179.     }
  180. /*
  181.  * If the caller asked for the attributes of the opened file, copy them over.
  182.  */
  183.     if (x) *x = xattr;
  184.  
  185. /*
  186.  * So far, so good. Let's get the device driver now, and try to
  187.  * actually open the file.
  188.  */
  189.     dev = (*fc.fs->getdev)(&fc, &devsp);
  190.     if (!dev) {
  191.         mint_errno = (int)devsp;
  192.         DEBUG(("do_open(%s): device driver not found",name));
  193.         release_cookie(&dir);
  194.         release_cookie(&fc);
  195.         return NULL;
  196.     }
  197.  
  198.     if (dev == &fakedev) {        /* fake BIOS devices */
  199.         f = curproc->handle[devsp];
  200.         if (!f) {
  201.             mint_errno = EIHNDL;
  202.             return 0;
  203.         }
  204.         f->links++;
  205.         release_cookie(&dir);
  206.         release_cookie(&fc);
  207.         return f;
  208.     }
  209.     if (0 == (f = new_fileptr())) {
  210.         release_cookie(&dir);
  211.         release_cookie(&fc);
  212.         mint_errno = ENSMEM;
  213.         return NULL;
  214.     }
  215.     f->links = 1;
  216.     f->flags = rwmode;
  217.     f->pos = 0;
  218.     f->devinfo = devsp;
  219.     f->fc = fc;
  220.     f->dev = dev;
  221.     release_cookie(&dir);
  222.  
  223.     r = (*dev->open)(f);
  224.     if (r < 0) {
  225.         DEBUG(("do_open(%s): device open failed with error %ld",
  226.             name, r));
  227.         mint_errno = (int)r;
  228.         f->links = 0;
  229.         release_cookie(&fc);
  230.         dispose_fileptr(f);
  231.         return NULL;
  232.     }
  233.  
  234. /* special code for opening a tty */
  235.     if (is_terminal(f)) {
  236.         extern struct tty default_tty;    /* in tty.c */
  237.  
  238.         tty = (struct tty *)f->devinfo;
  239.         if (tty->use_cnt == 0) {     /* first open for this device? */
  240.             *tty = default_tty;
  241.         }
  242.         tty->use_cnt++;
  243.     }
  244.     return f;
  245. }
  246.  
  247. /*
  248.  * helper function for do_close: this closes the indicated file pointer which
  249.  * is assumed to be associated with process p. The extra parameter is necessary
  250.  * because f_midipipe mucks with file pointers of other processes, so
  251.  * sometimes p != curproc.
  252.  *
  253.  * Note that the function changedrv() in filesys.c can call this routine.
  254.  * in that case, f->dev will be 0 to represent an invalid device, and
  255.  * we cannot call the device close routine.
  256.  */
  257.  
  258. long
  259. do_pclose(p, f)
  260.     PROC *p;
  261.     FILEPTR *f;
  262. {
  263.     long r = 0;
  264.  
  265.     if (!f) return EIHNDL;
  266.  
  267. /* if this file is "select'd" by this process, unselect it
  268.  * (this is just in case we were killed by a signal)
  269.  */
  270.  
  271. /* BUG? Feature? If media change is detected while we're doing the select,
  272.  * we'll never unselect (since f->dev is set to NULL by changedrv())
  273.  */
  274.     if (f->dev) {
  275.         (*f->dev->unselect)(f, (long)p, O_RDONLY);
  276.         (*f->dev->unselect)(f, (long)p, O_WRONLY);
  277.     }
  278.  
  279.     f->links--;
  280.  
  281. /* TTY manipulation must be done *before* calling the device close routine,
  282.  * since afterwards the TTY structure may no longer exist
  283.  */
  284.     if (is_terminal(f) && f->links <= 0) {
  285.         struct tty *tty = (struct tty *)f->devinfo;
  286.         tty->use_cnt--;
  287.         if (tty->use_cnt <= 0)
  288.             tty->pgrp = 0;
  289.         if (tty->use_cnt <= 0 && tty->xkey) {
  290.             kfree(tty->xkey);
  291.             tty->xkey = 0;
  292.         }
  293.     }
  294.  
  295.     if (f->dev) {
  296.         r = (*f->dev->close)(f, p->pid);
  297.         if (r) {
  298.             DEBUG(("close: device close failed"));
  299.         }
  300.     }
  301.     if (f->links <= 0) {
  302.         release_cookie(&f->fc);
  303.         dispose_fileptr(f);
  304.     }
  305.     return  r;
  306. }
  307.  
  308. long
  309. do_close(f)
  310.     FILEPTR *f;
  311. {
  312.     return do_pclose(curproc, f);
  313. }
  314.  
  315. long ARGS_ON_STACK
  316. f_open(name, mode)
  317.     const char *name;
  318.     int mode;
  319. {
  320.     int i;
  321.     FILEPTR *f;
  322.     PROC *proc;
  323.  
  324.     TRACE(("Fopen(%s, %x)", name, mode));
  325. #if O_GLOBAL
  326.     if (mode & O_GLOBAL) {
  327.         /* oh, boy! user wants us to open a global handle! */
  328.         proc = rootproc;
  329.     }
  330.     else
  331. #endif
  332.         proc = curproc;
  333.  
  334.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  335.         if (!proc->handle[i])
  336.             goto found_for_open;
  337.     }
  338.     DEBUG(("Fopen(%s): process out of handles",name));
  339.     return ENHNDL;        /* no more handles */
  340.  
  341. found_for_open:
  342.     mode &= O_USER;        /* make sure the mode is legal */
  343.  
  344. /* note: file mode 3 is reserved for the kernel; for users, transmogrify it
  345.  * into O_RDWR (mode 2)
  346.  */
  347.     if ( (mode & O_RWMODE) == O_EXEC ) {
  348.         mode = (mode & ~O_RWMODE) | O_RDWR;
  349.     }
  350.  
  351.     proc->handle[i] = (FILEPTR *)1;    /* reserve this handle */
  352.     f = do_open(name, mode, 0, (XATTR *)0);
  353.     proc->handle[i] = (FILEPTR *)0;
  354.  
  355.     if (!f) {
  356.         return mint_errno;
  357.     }
  358.     proc->handle[i] = f;
  359. /* default is to close non-standard files on exec */
  360.     proc->fdflags[i] = FD_CLOEXEC;
  361.  
  362. #if O_GLOBAL
  363.     if (proc != curproc) {
  364.         /* we just opened a global handle */
  365.         i += 100;
  366.     }
  367. #endif
  368.  
  369.     TRACE(("Fopen: returning %d", i));
  370.     return i;
  371. }
  372.  
  373. long ARGS_ON_STACK
  374. f_create(name, attrib)
  375.     const char *name;
  376.     int attrib;
  377. {
  378.     fcookie dir;
  379.     int i;
  380.     FILEPTR *f;
  381.     long r;
  382.     PROC *proc;
  383.     int offset = 0;
  384.     char temp1[PATH_MAX];
  385.  
  386.     TRACE(("Fcreate(%s, %x)", name, attrib));
  387. #if O_GLOBAL
  388.     if (attrib & O_GLOBAL) {
  389.         proc = rootproc;
  390.         offset = 100;
  391.         attrib &= ~O_GLOBAL;
  392.     }
  393.     else
  394. #endif
  395.         proc = curproc;
  396.  
  397.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  398.         if (!proc->handle[i])
  399.             goto found_for_create;
  400.     }
  401.     DEBUG(("Fcreate(%s): process out of handles",name));
  402.     return ENHNDL;        /* no more handles */
  403.  
  404. found_for_create:
  405.     if (attrib == FA_LABEL) {
  406.         r = path2cookie(name, temp1, &dir);
  407.         if (r) return r;
  408.         r = (*dir.fs->writelabel)(&dir, temp1);
  409.         release_cookie(&dir);
  410.         if (r) return r;
  411. /*
  412.  * just in case the caller tries to do something with this handle,
  413.  * make it point to u:\dev\null
  414.  */
  415.         f = do_open("u:\\dev\\null", O_RDWR|O_CREAT|O_TRUNC, 0,
  416.                  (XATTR *)0);
  417.         proc->handle[i] = f;
  418.         proc->fdflags[i] = FD_CLOEXEC;
  419.         return i+offset;
  420.     }
  421.     if (attrib & (FA_LABEL|FA_DIR)) {
  422.         DEBUG(("Fcreate(%s,%x): illegal attributes",name,attrib));
  423.         return EACCDN;
  424.     }
  425.  
  426.     proc->handle[i] = (FILEPTR *)1;        /* reserve this handle */
  427.     f = do_open(name, O_RDWR|O_CREAT|O_TRUNC, attrib, (XATTR *)0);
  428.     proc->handle[i] = (FILEPTR *)0;
  429.  
  430.     if (!f) {
  431.         DEBUG(("Fcreate(%s) failed, error %d", name, mint_errno));
  432.         return mint_errno;
  433.     }
  434.     proc->handle[i] = f;
  435.     proc->fdflags[i] = FD_CLOEXEC;
  436.     i += offset;
  437.     TRACE(("Fcreate: returning %d", i));
  438.     return i;
  439. }
  440.  
  441. long ARGS_ON_STACK
  442. f_close(fh)
  443.     int fh;
  444. {
  445.     FILEPTR *f;
  446.     long r;
  447.     PROC *proc;
  448.  
  449.     TRACE(("Fclose: %d", fh));
  450. #if O_GLOBAL
  451.     if (fh >= 100) {
  452.         fh -= 100;
  453.         proc = rootproc;
  454.     }
  455.     else
  456. #endif
  457.         proc = curproc;
  458.  
  459.     if (fh < 0 || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  460.         return EIHNDL;
  461.     }
  462.     r = do_pclose(proc, f);
  463.  
  464. /* standard handles should be restored to default values */
  465. /* do this for TOS domain only! */
  466.     if (proc->domain == DOM_TOS) {
  467.         if (fh == 0 || fh == 1)
  468.             f = proc->handle[-1];
  469.         else if (fh == 2 || fh == 3)
  470.             f = proc->handle[-fh];
  471.         else
  472.             f = 0;
  473.     } else
  474.         f = 0;
  475.  
  476.     if (f) {
  477.         f->links++;
  478.         proc->fdflags[fh] = 0;
  479.     }
  480.     proc->handle[fh] = f;
  481.     return r;
  482. }
  483.  
  484. long ARGS_ON_STACK
  485. f_read(fh, count, buf)
  486.     int fh;
  487.     long count;
  488.     char *buf;
  489. {
  490.     FILEPTR *f;
  491.  
  492.     PROC *proc;
  493.  
  494. #if O_GLOBAL
  495.     if (fh >= 100) {
  496.         fh -= 100;
  497.         proc = rootproc;
  498.     }
  499.     else
  500. #endif
  501.         proc = curproc;
  502.  
  503.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  504.         DEBUG(("Fread: invalid handle: %d", fh));
  505.         return EIHNDL;
  506.     }
  507.     if ( (f->flags & O_RWMODE) == O_WRONLY ) {
  508.         DEBUG(("Fread: read on a write-only handle"));
  509.         return EACCDN;
  510.     }
  511.     if (is_terminal(f))
  512.         return tty_read(f, buf, count);
  513.  
  514.     TRACELOW(("Fread: %ld bytes from handle %d to %lx", count, fh, buf));
  515.     return (*f->dev->read)(f, buf, count);
  516. }
  517.  
  518. long ARGS_ON_STACK
  519. f_write(fh, count, buf)
  520.     int fh;
  521.     long count;
  522.     const char *buf;
  523. {
  524.     FILEPTR *f;
  525.     PROC *proc;
  526.     long r;
  527.  
  528. #if O_GLOBAL
  529.     if (fh >= 100) {
  530.         fh -= 100;
  531.         proc = rootproc;
  532.     }
  533.     else
  534. #endif
  535.         proc = curproc;
  536.  
  537.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  538.         DEBUG(("Fwrite: bad handle: %d", fh));
  539.         return EIHNDL;
  540.     }
  541.     if ( (f->flags & O_RWMODE) == O_RDONLY ) {
  542.         DEBUG(("Fwrite: write on a read-only handle"));
  543.         return EACCDN;
  544.     }
  545.     if (is_terminal(f))
  546.         return tty_write(f, buf, count);
  547.  
  548.     /* it would be faster to do this in the device driver, but this
  549.      * way the drivers are easier to write
  550.      */
  551.     if (f->flags & O_APPEND) {
  552.         r = (*f->dev->lseek)(f, 0L, SEEK_END);
  553.         /* ignore errors from unseekable files (e.g. pipes) */
  554.         if (r == EACCDN)
  555.             r = 0;
  556.     } else
  557.         r = 0;
  558.     if (r >= 0) {
  559.         TRACELOW(("Fwrite: %ld bytes to handle %d", count, fh));
  560.         r = (*f->dev->write)(f, buf, count);
  561.     }
  562.     if (r < 0) {
  563.         DEBUG(("Fwrite: error %ld", r));
  564.     }
  565.     return r;
  566. }
  567.  
  568. long ARGS_ON_STACK
  569. f_seek(place, fh, how)
  570.     long place;
  571.     int fh;
  572.     int how;
  573. {
  574.     FILEPTR *f;
  575.     PROC *proc;
  576.  
  577.     TRACE(("Fseek(%ld, %d) on handle %d", place, how, fh));
  578. #if O_GLOBAL
  579.     if (fh >= 100) {
  580.         fh -= 100;
  581.         proc = rootproc;
  582.     }
  583.     else
  584. #endif
  585.         proc = curproc;
  586.  
  587.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  588.         DEBUG(("Fseek: bad handle: %d", fh));
  589.         return EIHNDL;
  590.     }
  591.     if (is_terminal(f)) {
  592.         return 0;
  593.     }
  594.     return (*f->dev->lseek)(f, place, how);
  595. }
  596.  
  597. /* duplicate file pointer fh; returns a new file pointer >= min, if
  598.    one exists, or ENHNDL if not. called by f_dup and f_cntl
  599.  */
  600.  
  601. static long do_dup(fh, min)
  602.     int fh, min;
  603. {
  604.     FILEPTR *f;
  605.     int i;
  606.     PROC *proc;
  607.  
  608.     for (i = min; i < MAX_OPEN; i++) {
  609.         if (!curproc->handle[i])
  610.             goto found;
  611.     }
  612.     return ENHNDL;        /* no more handles */
  613. found:
  614. #if O_GLOBAL
  615.     if (fh >= 100) {
  616.         fh -= 100;
  617.         proc = rootproc;
  618.     } else
  619. #endif
  620.         proc = curproc;
  621.  
  622.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh]))
  623.         return EIHNDL;
  624.  
  625.     curproc->handle[i] = f;
  626.  
  627. /* set default file descriptor flags */
  628.     if (i >= 0) {
  629.         if (i >= MIN_OPEN)
  630.             curproc->fdflags[i] = FD_CLOEXEC;
  631.         else
  632.             curproc->fdflags[i] = 0;
  633.     }
  634.     f->links++;
  635.     return i;
  636. }
  637.  
  638. long ARGS_ON_STACK
  639. f_dup(fh)
  640.     int fh;
  641. {
  642.     long r;
  643.     r = do_dup(fh, MIN_OPEN);
  644.     TRACE(("Fdup(%d) -> %ld", fh, r));
  645.     return r;
  646. }
  647.  
  648. long ARGS_ON_STACK
  649. f_force(newh, oldh)
  650.     int newh;
  651.     int oldh;
  652. {
  653.     FILEPTR *f;
  654.     PROC *proc;
  655.  
  656.     TRACE(("Fforce(%d, %d)", newh, oldh));
  657.  
  658. #if O_GLOBAL
  659.     if (oldh >= 100) {
  660.         oldh -= 100;
  661.         proc = rootproc;
  662.     } else
  663. #endif
  664.         proc = curproc;
  665.  
  666.     if (oldh < MIN_HANDLE || oldh >= MAX_OPEN ||
  667.         0 == (f = proc->handle[oldh])) {
  668.         DEBUG(("Fforce: old handle invalid"));
  669.         return EIHNDL;
  670.     }
  671.  
  672.     if (newh < MIN_HANDLE || newh >= MAX_OPEN) {
  673.         DEBUG(("Fforce: new handle out of range"));
  674.         return EIHNDL;
  675.     }
  676.  
  677.     (void)do_close(curproc->handle[newh]);
  678.     curproc->handle[newh] = f;
  679.     /* set default file descriptor flags */
  680.     if (newh >= 0)
  681.         curproc->fdflags[newh] = (newh >= MIN_OPEN) ? FD_CLOEXEC : 0;
  682.     f->links++;
  683. /*
  684.  * special: for a tty, if this is becoming a control terminal and the
  685.  * tty doesn't have a pgrp yet, make it have the pgrp of the process
  686.  * doing the Fforce
  687.  */
  688.     if (is_terminal(f) && newh == -1) {
  689.         struct tty *tty = (struct tty *)f->devinfo;
  690.  
  691.         if (!tty->pgrp)
  692.             tty->pgrp = curproc->pgrp;
  693.     }
  694.     return 0;
  695. }
  696.  
  697. long ARGS_ON_STACK
  698. f_datime(timeptr, fh, rwflag)
  699.     short *timeptr;
  700.     int fh;
  701.     int rwflag;
  702. {
  703.     FILEPTR *f;
  704.     PROC *proc;
  705.  
  706.     TRACE(("Fdatime(%d)", fh));
  707. #if O_GLOBAL
  708.     if (fh >= 100) {
  709.         fh -= 100;
  710.         proc = rootproc;
  711.     }
  712.     else
  713. #endif
  714.         proc = curproc;
  715.  
  716.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  717.         DEBUG(("Fdatime: invalid handle"));
  718.         return EIHNDL;
  719.     }
  720.  
  721. /* some programs use Fdatime to test for TTY devices */
  722.     if (is_terminal(f))
  723.         return EACCDN;
  724.  
  725.     return (*f->dev->datime)(f, timeptr, rwflag);
  726. }
  727.  
  728. long ARGS_ON_STACK
  729. f_lock(fh, mode, start, length)
  730.     int fh, mode;
  731.     long start, length;
  732. {
  733.     FILEPTR *f;
  734.     struct flock lock;
  735.     PROC *proc;
  736.  
  737. #if O_GLOBAL
  738.     if (fh >= 100) {
  739.         fh -= 100;
  740.         proc = rootproc;
  741.     }
  742.     else
  743. #endif
  744.         proc = curproc;
  745.  
  746.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  747.         DEBUG(("Flock: invalid handle"));
  748.         return EIHNDL;
  749.     }
  750.     TRACE(("Flock(%d,%d,%ld,%ld)", fh, mode, start, length));
  751.     lock.l_whence = SEEK_SET;
  752.     lock.l_start = start;
  753.     lock.l_len = length;
  754.  
  755.     if (mode == 0)        /* create a lock */
  756.         lock.l_type = F_WRLCK;
  757.     else if (mode == 1)    /* unlock region */
  758.         lock.l_type = F_UNLCK;
  759.     else
  760.         return EINVFN;
  761.  
  762.     return (*f->dev->ioctl)(f, F_SETLK, &lock);
  763. }
  764.  
  765. /*
  766.  * extensions to GEMDOS:
  767.  */
  768.  
  769. /*
  770.  * Fpipe(int *handles): opens a pipe. if successful, returns 0, and
  771.  * sets handles[0] to a file descriptor for the read end of the pipe
  772.  * and handles[1] to one for the write end.
  773.  */
  774.  
  775. long ARGS_ON_STACK
  776. f_pipe(usrh)
  777.     short *usrh;
  778. {
  779.     FILEPTR *in, *out;
  780.     static int pipeno = 0;
  781.     int i, j;
  782.     char pipename[32]; /* MAGIC: 32 >= strlen "u:\pipe\sys$pipe.000\0" */
  783.  
  784.     TRACE(("Fpipe"));
  785.  
  786. /* BUG: more than 999 open pipes hangs the system */
  787.     do {
  788.         ksprintf(pipename, "u:\\pipe\\sys$pipe.%03d", pipeno);
  789.         pipeno++; if (pipeno > 999) pipeno = 0;
  790.         out = do_open(pipename, O_WRONLY|O_CREAT|O_EXCL, FA_RDONLY|FA_HIDDEN|FA_CHANGED,
  791.                  (XATTR *)0);
  792.             /* read-only attribute means unidirectional fifo */
  793.             /* hidden attribute means check for broken pipes */
  794.             /* changed attribute means act like Unix fifos */
  795.     } while (out == 0 && mint_errno == EACCDN);
  796.  
  797.     if (!out) {
  798.         DEBUG(("Fpipe: error %d", mint_errno));
  799.         return mint_errno;
  800.     }
  801.  
  802.     in = do_open(pipename, O_RDONLY, 0, (XATTR *)0);
  803.     if (!in) {
  804.         DEBUG(("Fpipe: in side of pipe not opened (error %d)",
  805.             mint_errno));
  806.         (void)do_close(out);
  807.         return mint_errno;
  808.     }
  809.  
  810.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  811.         if (curproc->handle[i] == 0)
  812.             break;
  813.     }
  814.  
  815.     for (j = i+1; j < MAX_OPEN; j++) {
  816.         if (curproc->handle[j] == 0)
  817.             break;
  818.     }
  819.  
  820.     if (j >= MAX_OPEN) {
  821.         DEBUG(("Fpipe: not enough handles left"));
  822.         (void) do_close(in);
  823.         (void) do_close(out);
  824.         return ENHNDL;
  825.     }
  826.     curproc->handle[i] = in; curproc->handle[j] = out;
  827. /* leave pipes open across Pexec */
  828.     curproc->fdflags[i] = 0;
  829.     curproc->fdflags[j] = 0;
  830.  
  831.     usrh[0] = i;
  832.     usrh[1] = j;
  833.     TRACE(("Fpipe: returning 0: input %d output %d",i,j));
  834.     return 0;
  835. }
  836.  
  837. /*
  838.  * f_cntl: a combination "ioctl" and "fcntl". Some functions are
  839.  * handled here, if they apply to the file descriptors directly
  840.  * (e.g. F_DUPFD) or if they're easily translated into file system
  841.  * functions (e.g. FSTAT). Others are passed on to the device driver
  842.  * via dev->ioctl.
  843.  */
  844.  
  845. long ARGS_ON_STACK
  846. f_cntl(fh, arg, cmd)
  847.     int fh;
  848.     long arg;
  849.     int cmd;
  850. {
  851.     FILEPTR    *f;
  852.     PROC *proc;
  853.     struct flock *fl;
  854.     long r;
  855.  
  856.     TRACE(("Fcntl(%d, cmd=0x%x)", fh, cmd));
  857. #if O_GLOBAL
  858.     if (fh >= 100) {
  859.         fh -= 100;
  860.         proc = rootproc;
  861.     }
  862.     else
  863. #endif
  864.         proc = curproc;
  865.  
  866.     if (fh < MIN_HANDLE || fh >= MAX_OPEN) {
  867.         DEBUG(("Fcntl: bad file handle"));
  868.         return EIHNDL;
  869.     }
  870.  
  871.     if (cmd == F_DUPFD) {
  872. #if O_GLOBAL
  873.         if (proc != curproc) fh += 100;
  874. #endif
  875.           return do_dup(fh, (int)arg);
  876.     }
  877.  
  878.     f = proc->handle[fh];
  879.     if (!f) return EIHNDL;
  880.  
  881.     switch(cmd) {
  882.     case F_GETFD:
  883.         TRACE(("Fcntl F_GETFD"));
  884.         if (fh < 0) return EIHNDL;
  885.         return proc->fdflags[fh];
  886.     case F_SETFD:
  887.         TRACE(("Fcntl F_SETFD"));
  888.         if (fh < 0) return EIHNDL;
  889.         proc->fdflags[fh] = arg;
  890.         return 0;
  891.     case F_GETFL:
  892.         TRACE(("Fcntl F_GETFL"));
  893.         return f->flags & O_USER;
  894.     case F_SETFL:
  895.         TRACE(("Fcntl F_SETFL"));
  896.         arg &= O_USER;        /* make sure only user bits set */
  897. #if 0
  898.     /* COMPATIBILITY WITH OLD VERSIONS ONLY */
  899.     /* THIS CODE WILL GO AWAY. REALLY! */
  900.         if (arg & 4) {
  901.             arg |= O_NDELAY;
  902.             arg &= ~4;
  903.         }
  904. #endif
  905.  
  906.     /* make sure the file access and sharing modes are not changed */
  907.         arg &= ~(O_RWMODE|O_SHMODE);
  908.         arg |= f->flags & (O_RWMODE|O_SHMODE);
  909.         f->flags &= ~O_USER;    /* set user bits to arg */
  910.         f->flags |= arg;
  911.         return 0;
  912.     case FSTAT:
  913.         return (*f->fc.fs->getxattr)(&f->fc, (XATTR *)arg);
  914.     case F_SETLK:
  915.     case F_SETLKW:
  916.     /* make sure that the file was opened with appropriate permissions */
  917.         fl = (struct flock *)arg;
  918.         if (fl->l_type == F_RDLCK) {
  919.             if ( (f->flags & O_RWMODE) == O_WRONLY )
  920.                 return EACCDN;
  921.         } else {
  922.             if ( (f->flags & O_RWMODE) == O_RDONLY )
  923.                 return EACCDN;
  924.         }
  925.         /* fall through to device ioctl */
  926.     default:
  927.         TRACE(("Fcntl mode %x: calling ioctl",cmd));
  928.         r = (*f->dev->ioctl)(f, cmd, (void *)arg);
  929.         if (r == EINVFN && is_terminal(f)) {
  930.             r = tty_ioctl(f, cmd, (void *)arg);
  931.         }
  932.         return r;
  933.     }
  934. }
  935.  
  936. /*
  937.  * fselect(timeout, rfd, wfd, xfd)
  938.  * timeout is an (unsigned) 16 bit integer giving the maximum number
  939.  * of milliseconds to wait; rfd, wfd, and xfd are pointers to 32 bit
  940.  * integers containing bitmasks that describe which file descriptors
  941.  * we're interested in. These masks are changed to represent which
  942.  * file descriptors actually have data waiting (rfd), are ready to
  943.  * output (wfd), or have exceptional conditions (xfd -- currently
  944.  * ignored). If timeout is 0, fselect blocks until some file descriptor
  945.  * is ready; otherwise, it waits only "timeout" milliseconds.
  946.  * Return value: number of file descriptors that are available for
  947.  * reading/writing; or a negative error number.
  948.  */
  949.  
  950. /* helper function for time outs */
  951. static void
  952. unselectme(p)
  953.     PROC *p;
  954. {
  955.     wakeselect((long)p);
  956. }
  957.  
  958. long ARGS_ON_STACK
  959. f_select(timeout, rfdp, wfdp, xfdp)
  960.     unsigned timeout;
  961.     long *rfdp, *wfdp, *xfdp;
  962. {
  963.     long rfd, wfd;
  964.     long mask, bytes;
  965.     int i, count;
  966.     FILEPTR *f;
  967.     PROC *p;
  968.     TIMEOUT *t;
  969.     short sr;
  970.  
  971.     if (xfdp)
  972.         *xfdp = 0;
  973.  
  974.     if (rfdp) {
  975.         rfd = *rfdp; *rfdp = 0;
  976.     }
  977.     else
  978.         rfd = 0;
  979.     if (wfdp) {
  980.         wfd = *wfdp; *wfdp = 0;
  981.     }
  982.     else
  983.         wfd = 0;
  984.  
  985.     TRACE(("Fselect(%u, %lx, %lx)", timeout, rfd, wfd));
  986.     p = curproc;            /* help the optimizer out */
  987.  
  988.     /* first, validate the masks */
  989.     mask = 1L;
  990.     for (i = 0; i < MAX_OPEN; i++) {
  991.         if ( ((rfd & mask) || (wfd & mask)) && !(p->handle[i]) ) {
  992.             DEBUG(("Fselect: invalid handle: %d", i));
  993.             return EIHNDL;
  994.         }
  995.         mask = mask << 1L;
  996.     }
  997.  
  998. /* now, loop through the file descriptors, setting up the select process */
  999. /* NOTE: wakeselect will set p->wait_cond to 0 if data arrives during the
  1000.  * selection
  1001.  * Also note: because of the validation above, we may assume that the
  1002.  * file handles are valid here. However, this assumption may no longer
  1003.  * be true after we've gone to sleep, since a signal handler may have
  1004.  * closed one of the handles.
  1005.  */
  1006.  
  1007.     mask = 1L;
  1008.     count = 0;
  1009.     curproc->wait_cond = (long)wakeselect;        /* flag */
  1010.  
  1011.     for (i = 0; i < MAX_OPEN; i++) {
  1012.         if (rfd & mask) {
  1013.             f = p->handle[i];
  1014.             if ((*f->dev->select)(f, (long)p, O_RDONLY) == 1) {
  1015.                 count++;
  1016.                 *rfdp |= mask;
  1017.             }
  1018.         }
  1019.         if (wfd & mask) {
  1020.             f = p->handle[i];
  1021.             if ((*f->dev->select)(f, (long)p, O_WRONLY) == 1) {
  1022.                 count++;
  1023.                 *wfdp |= mask;
  1024.             }
  1025.         }
  1026.         mask = mask << 1L;
  1027.     }
  1028.  
  1029.     if (count == 0) {
  1030.         /* OK, now let's set a timeout */
  1031.  
  1032.         if (timeout) {
  1033.             t = addtimeout((long)timeout, unselectme);
  1034.         } else {
  1035.             t = 0;
  1036.         }
  1037.  
  1038.         sr = spl7();
  1039.  
  1040.     /* curproc->wait_cond changes when data arrives or the timeout happens */
  1041.         while (curproc->wait_cond == (long)wakeselect) {
  1042.             TRACE(("sleeping in Fselect"));
  1043.             sleep(SELECT_Q, (long)wakeselect);
  1044.         }
  1045.         spl(sr);
  1046.  
  1047.     /* we can cancel the time out now (if it hasn't already happened) */
  1048.         if (t) canceltimeout(t);
  1049.  
  1050.     /* OK, let's see what data arrived (if any) */
  1051.         mask = 1L;
  1052.         for (i = 0; i < MAX_OPEN; i++) {
  1053.             if (rfd & mask) {
  1054.                 f = p->handle[i];
  1055.                 if (f) {
  1056.                     bytes = 1L;
  1057.                     (void)(*f->dev->ioctl)(f, FIONREAD,&bytes);
  1058.                     if (bytes > 0) {
  1059.                     *rfdp |= mask;
  1060.                     count++;
  1061.                     }
  1062.                 }
  1063.             }
  1064.             if (wfd & mask) {
  1065.                 f = p->handle[i];
  1066.                 if (f) {
  1067.                     bytes = 1L;
  1068.                     (void)(*f->dev->ioctl)(f, FIONWRITE,&bytes);
  1069.                     if (bytes > 0) {
  1070.                     *wfdp |= mask;
  1071.                     count++;
  1072.                     }
  1073.                 }
  1074.             }
  1075.             mask = mask << 1L;
  1076.         }
  1077.     }
  1078.  
  1079.     /* at this point, we either have data or a time out */
  1080.     /* cancel all the selects */
  1081.     mask = 1L;
  1082.  
  1083.     for (i = 0; i < MAX_OPEN; i++) {
  1084.         if (rfd & mask) {
  1085.             f = p->handle[i];
  1086.             if (f)
  1087.                 (*f->dev->unselect)(f, (long)p, O_RDONLY);
  1088.         }
  1089.         if (wfd & mask) {
  1090.             f = p->handle[i];
  1091.             if (f)
  1092.                 (*f->dev->unselect)(f, (long)p, O_WRONLY);
  1093.         }
  1094.         mask = mask << 1L;
  1095.     }
  1096.  
  1097.     TRACE(("Fselect: returning %d", count));
  1098.     return count;
  1099. }
  1100.  
  1101.  
  1102. /*
  1103.  * GEMDOS extension: Fmidipipe
  1104.  * Fmidipipe(pid, in, out) manipultes the MIDI file handles (handles -4 and -5)
  1105.  * of process "pid" so that they now point to the files with handles "in" and
  1106.  * "out" in the calling process
  1107.  */
  1108.  
  1109. long ARGS_ON_STACK
  1110. f_midipipe(pid, in, out)
  1111.     int pid, in, out;
  1112. {
  1113.     PROC *p;
  1114.     FILEPTR *fin, *fout;
  1115.  
  1116. /* first, find the process */
  1117.  
  1118.     if (pid == 0)
  1119.         p = curproc;
  1120.     else {
  1121.         p = pid2proc(pid);
  1122.         if (!p)
  1123.             return EFILNF;
  1124.     }
  1125.  
  1126. /* next, validate the input and output file handles */
  1127.     if (in < MIN_HANDLE || in >= MAX_OPEN || (0==(fin = curproc->handle[in])))
  1128.         return EIHNDL;
  1129.     if ( (fin->flags & O_RWMODE) == O_WRONLY ) {
  1130.         DEBUG(("Fmidipipe: input side is write only"));
  1131.         return EACCDN;
  1132.     }
  1133.     if (out < MIN_HANDLE || out >= MAX_OPEN || (0==(fout = curproc->handle[out])))
  1134.         return EIHNDL;
  1135.     if ( (fout->flags & O_RWMODE) == O_RDONLY ) {
  1136.         DEBUG(("Fmidipipe: output side is read only"));
  1137.         return EACCDN;
  1138.     }
  1139.  
  1140. /* OK, duplicate the handles and put them in the new process */
  1141.     fin->links++; fout->links++;
  1142.     (void)do_pclose(p, p->midiin);
  1143.     (void)do_pclose(p, p->midiout);
  1144.     p->midiin = fin; p->midiout = fout;
  1145.     return 0;
  1146. }
  1147.